﻿using mozhi.smarterp.Finance.Accounts;
using mozhi.smarterp.Finance.Accounts.Repository;
using mozhi.smarterp.Finance.Basedatas.Customers;
using mozhi.smarterp.Finance.Basedatas.Events;
using mozhi.smarterp.Finance.Basedatas.Products;
using mozhi.smarterp.Finance.Basedatas.Repository;
using mozhi.smarterp.Finance.Basedatas.ThirdParties;
using mozhi.smarterp.Finance.Enums;
using mozhi.smarterp.Finance.Querys;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.Application.Dtos;
using Volo.Abp.EventBus.Distributed;
using Volo.Abp.Guids;
using Volo.Abp.ObjectMapping;

namespace mozhi.smarterp.Finance.Basedatas
{
    public class ProductAppService : BaseDataAppService<Product, ProductDto, ProductCreateDto, ProductUpdateDto>, IProductAppService
    {
        private IAccountRepository _accountRepository;

        public ProductAppService(IBaseDataRepository<Product> repository, IDataAssociationRepository dataAssociationRepository,
            IGuidGenerator guidGenerator, IDistributedEventBus distributedEventBus , IAccountRepository accountRepository)
            : base(repository, dataAssociationRepository, guidGenerator, distributedEventBus)
        {
            _accountRepository = accountRepository;
        }


        public override async Task<PagedResultDto<ProductDto>> FindAsync(PageQuery query)
        {
            var result = await base.FindAsync(query);

            var products = result.Items.ToList();

            if (products.Count == 0)
                return result;

            await LoadAccountInfoAsync(products);

            return result;
        }

        public override async Task<ProductDto> CreateAsync(ProductCreateDto dto)
        {
            await Validate(null, dto.Code, dto.Name);

            await ValidateAccount(dto.Type, dto.StockAccountId, dto.RevenueAccountId, dto.CostAccountId, dto.ExpenseAccountId);

            var product = new Product(_guidGenerator.Create(), dto.Code, dto.Name , dto.Type , dto.StockAccountId , dto.RevenueAccountId , dto.CostAccountId , dto.ExpenseAccountId);

            product = await _repository.InsertAsync(product);

            var result = ObjectMapper.Map<Product, ProductDto>(product);

            await LoadAccountInfoAsync(new List<ProductDto> { result });

            return result;
        }


        public override async Task<ProductDto> UpdateAsync(ProductUpdateDto dto)
        {
            var product = await _repository.GetAsync(dto.Id);

            if (product == null)
                throw new UserFriendlyException("产品不存在", "100000");

            var oldStockAccountId = product.StockAccountId;
            var oldRevenueAccountId = product.RevenueAccountId;
            var oldCostAccountId = product.CostAccountId;
            var oldExpenseAccountId = product.ExpenseAccountId;

            await Validate(dto.Id, dto.Code, dto.Name);

            await ValidateAccount(product.Type , dto.StockAccountId, dto.RevenueAccountId, dto.CostAccountId, dto.ExpenseAccountId);

            product.Change(dto.Code, dto.Name, dto.Activated);
            product.ChangeAccount(product.Type, dto.StockAccountId, dto.RevenueAccountId, dto.CostAccountId, dto.ExpenseAccountId);

            product = await _repository.UpdateAsync(product);

            var result = ObjectMapper.Map<Product,ProductDto>(product);

            await LoadAccountInfoAsync(new List<ProductDto>() { result });

            //await PublishEventAsync(product, oldStockAccountId, oldRevenueAccountId, oldCostAccountId, oldExpenseAccountId);

            return result;
        }

        #region
        private async Task LoadAccountInfoAsync(List<ProductDto> products)
        {
            var accountIds = products.Where(x => x.StockAccountId.HasValue).Select(x => x.StockAccountId.Value).Distinct().ToList();

            accountIds.AddRange(products.Where(x => x.RevenueAccountId.HasValue).Select(x => x.RevenueAccountId.Value).Distinct().ToList());

            accountIds.AddRange(products.Where(x => x.CostAccountId.HasValue).Select(x => x.CostAccountId.Value).Distinct().ToList());

            accountIds.AddRange(products.Where(x => x.ExpenseAccountId.HasValue).Select(x => x.ExpenseAccountId.Value).Distinct().ToList());

            accountIds = accountIds.Distinct().ToList();

            if (accountIds.Count == 0)
                return;

            var accounts = await _accountRepository.FindAsync(new AccountQuery() { Ids = accountIds });

            if (accounts.Count == 0)
                return;

            foreach (var product in products)
            {
                product.StockAccountName = accounts.FirstOrDefault(x => x.Id == product.StockAccountId)?.FullName;
                product.RevenueAccountName = accounts.FirstOrDefault(x => x.Id == product.RevenueAccountId)?.FullName;
                product.CostAccountName = accounts.FirstOrDefault(x => x.Id == product.CostAccountId)?.FullName;
                product.ExpenseAccountName = accounts.FirstOrDefault(x => x.Id == product.ExpenseAccountId)?.FullName;
            }
        }


        private async Task ValidateAccount(ProductType type,
            Guid? stockAccountId, Guid? revenueAccountId, Guid? costAccountId, Guid? expenseAccountId)
        {
            if (type == ProductType.Asset)
                return;

            var ids = new List<Guid>();

            if(type == ProductType.Stock)
            {
                if(stockAccountId.HasValue)
                    ids.Add(stockAccountId.Value);
                
                if (revenueAccountId.HasValue)
                    ids.Add(revenueAccountId.Value);

                if(costAccountId.HasValue)
                    ids.Add(costAccountId.Value);
            }
            else if(type == ProductType.Service)
            {
                if(expenseAccountId.HasValue)
                    ids.Add(expenseAccountId.Value);
            }

            if (ids.Count == 0)
                return;

            var accounts = await _accountRepository.FindAsync(new AccountQuery() { Ids = ids});

            if (stockAccountId.HasValue)
            {
                var matchAccount = accounts.FirstOrDefault(x => x.Id == stockAccountId);
                base.ValidateAccount(matchAccount, "库存科目");
            }

            if (revenueAccountId.HasValue)
            {
                var matchAccount = accounts.FirstOrDefault(x => x.Id == revenueAccountId);
                base.ValidateAccount(matchAccount, "收入科目");
            }

            if (costAccountId.HasValue)
            {
                var matchAccount = accounts.FirstOrDefault(x => x.Id == revenueAccountId);
                base.ValidateAccount(matchAccount, "成本科目");
            }

            if (expenseAccountId.HasValue)
            {
                var matchAccount = accounts.FirstOrDefault(x => x.Id == expenseAccountId);
                base.ValidateAccount(matchAccount, "费用科目");
            }
        }

        //private async Task PublishEventAsync(Product product, Guid? oldStockAccountId, Guid? oldRevenueAccountId, Guid? oldCostAccountId, Guid? oldExpenseAccountId, int? type = null)
        //{
        //    var events = new List<DataAssociationEvent>();

        //    if (product.StockAccountId.HasValue)
        //    {
        //        var eventData = new DataAssociationEvent(product.Id, nameof(Product), "产品", product.Code, product.Name, product.StockAccountId.Value, oldStockAccountId, nameof(Account), "科目", type);
        //        events.Add(eventData);
        //    }
           
        //    if (product.RevenueAccountId.HasValue)
        //    {
        //        var eventData = new DataAssociationEvent(product.Id, nameof(Product), "产品", product.Code, product.Name, product.RevenueAccountId.Value, oldRevenueAccountId, nameof(Account), "科目", type);
        //        events.Add(eventData);
        //    }
            

        //    if (product.CostAccountId.HasValue)
        //    {
        //        var eventData = new DataAssociationEvent(product.Id, nameof(Product), "产品", product.Code, product.Name, product.CostAccountId.Value, oldCostAccountId, nameof(Account), "科目", type);
        //        events.Add(eventData);
        //    }
           

        //    if (product.ExpenseAccountId.HasValue)
        //    {
        //        var eventData = new DataAssociationEvent(product.Id, nameof(Product), "产品", product.Code, product.Name, product.ExpenseAccountId.Value, oldExpenseAccountId, nameof(Account), "科目", type);
        //        events.Add(eventData);
        //    }
           

        //    await PublishDataAssociationEventAsync(events);
        //}

        #endregion
    }
}
